﻿using FluentParser.Expressions;
using FluentParser.Expressions.Rules.Composition;
using FluentParser.Utils;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace FluentParser.Tests.Expressions.Rules.Composition
{
    [TestClass]
    public class GroupExpressionRuleTests
    {
        [TestMethod]
        public void ParseT_WhenTwoValidNodes_ShouldReturnTheTuple()
        {
            Symbol leftToken = "LeftToken";
            Symbol rightToken = "RightToken";
            var token = new GroupExpressionRule<object, object, Tuple<object, object>>
                (leftToken, rightToken, Tuple.Create);
            ParsingResult<Tuple<object, object>> result = token.Parse("LeftTokenRightTokenAndSomethingElse");

            var expected = Tuple.Create<object, object>("LeftToken", "RightToken");
            var actual = result.Value;

            Assert.AreEqual(expected, actual);
            result.AssertLength("LeftTokenRightToken");
        }

        [TestMethod]
        public void ParseT_WhenSecondInvalid_ShouldReturnNull()
        {
            Symbol leftToken = "LeftToken";
            Symbol rightToken = "RightToken";
            var token = new GroupExpressionRule<object, object, Tuple<object, object>>
                (leftToken, rightToken, Tuple.Create);

            Tuple<string, string> expected = null;
            var actual = token.Parse("LeftTokenAndSomethingElse");

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ParseT_WhenBothInvalid_ShouldReturnNull()
        {
            Symbol leftToken = "LeftToken";
            Symbol rightToken = "RightToken";
            var token = new GroupExpressionRule<object, object, Tuple<object, object>>
                (leftToken, rightToken, Tuple.Create);

            Tuple<string, string> expected = null;
            var actual = token.Parse("LeftSomethingElse");

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ParseNodeT_WhenTwoValidNodes_ShouldReturnTheTuple()
        {
            Symbol leftToken = "LeftToken";
            Symbol rightToken = "RightToken";
            var token = new GroupExpressionRule<object, object, Tuple<object, object>>
                (leftToken, rightToken, Tuple.Create);
            ParsingNodeResult node = token.ParseNode("LeftTokenRightTokenAndSomethingElse");

            var expected = Tuple.Create<object, object>("LeftToken", "RightToken");
            var actual = node.Value as Tuple<object, object>;

            Assert.AreEqual(expected, actual);
            node.AssertLength("LeftTokenRightToken");
            node.AssertExploredLength("LeftTokenRightToken");

            node.AssertChildren(
                true, // LeftToken
                true); // RightToken
        }

        [TestMethod]
        public void ParseNodeT_WhenSecondInvalid_ShouldReturnNull()
        {
            Symbol leftToken = "LeftToken";
            Symbol rightToken = "RightToken";
            var token = new GroupExpressionRule<object, object, Tuple<object, object>>
                (leftToken, rightToken, Tuple.Create);
            ParsingNodeResult node = token.ParseNode("LeftTokenAndSomethingElse");

            Tuple<object, object> expected = null;
            var actual = node.Value as Tuple<object, object>;

            Assert.AreEqual(expected, actual);
            node.AssertLength("");
            node.AssertExploredLength("LeftToken?");

            node.AssertChildren(
                true, // LeftToken
                false); // RightToken
        }

        [TestMethod]
        public void ParseNodeT_WhenBothInvalid_ShouldReturnNull()
        {
            Symbol leftToken = "LeftToken";
            Symbol rightToken = "RightToken";
            var token = new GroupExpressionRule<object, object, Tuple<object, object>>
                (leftToken, rightToken, Tuple.Create);
            ParsingNodeResult node = token.ParseNode("LeftSomethingElse");

            Tuple<string, string> expected = null;
            var actual = node.Value as Tuple<string, string>;

            Assert.AreEqual(expected, actual);
            node.AssertLength("");
            node.AssertExploredLength("Left?");

            // Children check
            node.AssertChildren(
                false); // LeftToken
        }
    }
}
